/*
 * @Descripttion:
 * @Author: lukasavage
 * @Date: 2021-11-30 20:53:32
 * @LastEditors: lukasavage
 * @LastEditTime: 2022-10-19 14:48:26
 */

import { TAKE, PUT, FORK } from './effectTypes';
export default function runSaga(env, saga) {
	let { eventEmitter, dispatch } = env;
	let it = typeof saga === 'function' ? saga() : saga;
	function next(value) {
		let { value: effect, done } = it.next(value);
		if (!done) {
			if (typeof effect[Symbol.iterator] === 'function') {
				runSaga(env, effect);
				next(); //不会阻止当前saga继续向后走
			} else if (effect instanceof Promise) {
				effect.then(next);
			} else {
				switch (effect.type) {
					case TAKE:
						eventEmitter.once(effect.actionType, next);
						break;
					case PUT:
						dispatch(effect.action);
						next();
						break;
					case FORK:
						runSaga(env, effect.saga);
						next();
						break;
					case CALL:
						effect.fn(...effect.args).then(next);
						break;
					case effectTypes.CPS:
						effect.fn(...effect.args, (err, data) => {
							if (err) {
								next(err, true);
							} else {
								next(data);
							}
						});
						break;
					case ALL:
						const { iterators } = effect;
						let result = [];
						let counter = 0;
						iterators.forEach((iterator, index) => {
							runSaga(env, iterator, () => {
                                result[index] = data;
                                if(++counter === iterators.length) {
                                    next(result)
                                }
                            });
						});
						break;
					default:
						break;
				}
			}
		}
	}
	next();
}
